<!DOCTYPE HTML>
<html>
<head>
<style>
body {background-color: #000; overflow: hidden; margin: 5px}
#row1, #row2 {text-align: center}
</style>
<script>
var hh, mm, ss, ww, MM, dd, yy;
var timer;
var config = localStorage['config'];
if (config == undefined) {
	config = {
		only_hhmm: false,
		is24: false
		}
	var only_hhmm = localStorage['only_hhmm'];
	if (only_hhmm != undefined) {
		config.only_hhmm = only_hhmm;
		delete localStorage['only_hhmm'];
		}
	localStorage['config'] = JSON.stringify(config);
	}
else {
	config = JSON.parse(config);
	}
	
function Flip(target, text, font) {
	if (target === undefined) {
		return;
		}
	this.target = document.getElementById(target);
	this.text = text;
	this._from = document.createElement('canvas');
	this._to = document.createElement('canvas');
	this.step = null;
	this.max_steps = 10;
	this.resize(font);
	}
Flip.prototype = {
	constructor: Flip,
	resize: function (font) {
		if (this._from) {
			this._from.width = this.target.width;
			this._from.height = this.target.height;
			}
		if (this._to) {
			this._to.width = this.target.width;
			this._to.height = this.target.height;
			}
		
		this.font = font;
		this.fontsize = /^\d+/.exec(font)[0];
		// Calculate gap
		var gap = Math.floor(Number(this.fontsize) * 0.01);
		if (gap < 2) {
			gap = 2;
			}
		if (gap > 20) {
			gap = 20;
			}
		this.gap = gap;
		
		if (this.step !== null) {
			this._draw(this._from, this._oldtext);
			this._draw(this._to, this.text);
			}
		else {
			this._draw(this.target, this.text);
			}
		},
	_draw: function (target, text) {
		var ctx = target.getContext('2d');
		
		ctx.clearRect(0, 0, target.width, target.height);
		ctx.fillStyle = '#222';
		var r = Math.floor(this.fontsize * 0.1);
		ctx.beginPath();
		ctx.moveTo(r - 1, 0);
		ctx.lineTo(target.width - r - 1, 0);
		ctx.quadraticCurveTo(target.width - 1, 0, target.width - 1, r - 1);
		ctx.lineTo(target.width - 1, target.height - r - 1);
		ctx.quadraticCurveTo(target.width - 1, target.height - 1, target.width - r - 1, target.height - 1);
		ctx.lineTo(r - 1, target.height - 1);
		ctx.quadraticCurveTo(0, target.height - 1, 0, target.height - r - 1);
		ctx.lineTo(0, r - 1);
		ctx.quadraticCurveTo(0, 0, r - 1, 0);
		ctx.fill();

		ctx.fillStyle = '#fff';
		ctx.font = this.font;
		ctx.textAlign = 'center';
		ctx.textBaseline = 'middle';
		
		ctx.fillText(text, target.width / 2, target.height / 2);

		// Middle gap
		ctx.fillStyle = '#000';
		ctx.fillRect(0, target.height / 2 - this.gap / 2, target.width, this.gap);
		},
	flip: function (new_text) {
		if (this.text == new_text) {
			return;
			}
		if (this.step !== null) {
			// TODO add queue to get rid of this
			throw "I'm busy flipping your text!";
			}
		// set up _from, _to
		this._draw(this._from, this.text);
		this._draw(this._to, new_text);
		this.step = 0;
		this._flip();
		this._oldtext = this.text; // in case of resizing
		this.text = new_text;
		},
	_flip: function () {
		function flipit(flip) {
			var cd = flip.target.getContext('2d');
			var w = flip.target.width;
			var h = flip.target.height;
			
			if (flip.step <= flip.max_steps / 2) {
				cd.drawImage(flip._to,
					0, 0, w, h / 2,
					0, 0, w, h / 2);

				var sf_top = 1.0 * flip.step / (flip.max_steps / 2) * h / 2;
				cd.drawImage(flip._from,
					0, 0, w, h / 2,
					0, sf_top, w, h / 2 - sf_top);
				}
			if (flip.step === 0 || flip.step >= flip.max_steps / 2) {
				cd.drawImage(flip._from,
					0, h / 2, w, h / 2,
					0, h / 2, w, h / 2);
				}
			if (flip.step >= flip.max_steps / 2) {
				var st_top = (1.0 * flip.step / (flip.max_steps / 2) - 1) * h / 2;
				cd.drawImage(flip._to,
					0, h / 2, w, h / 2,
					0, h / 2, w, st_top);
				}

			flip.step++;
			if (flip.step<flip.max_steps) {
				window.setTimeout(function () {flipit(flip);}, 10);
				}
			else {
				cd.drawImage(flip._to,
					0, h / 2, w, h / 2,
					0, h / 2, w, h / 2);
				flip.step = null;
				}
			}
		var flip = this;
		window.setTimeout(function () {flipit(flip);}, 10);
		}
	};

function FlipHour(target, hour, font) {
	Flip.call(this, target, hour, font);
	this._draw(this.target, hour);
	}
FlipHour.prototype = new Flip();

FlipHour.prototype._draw = function (target, text) {
	var hour = Number(text);
	if (config.is24) {
		Flip.prototype._draw.call(this, target, hour);
		return;
		}
	Flip.prototype._draw.call(this, target, (hour > 12) ? hour - 12 : ((hour == 0)? '12' : hour));
	var ctx = target.getContext('2d');
	ctx.save();
	ctx.font = Math.floor(this.target.height * 0.1) + 'px Arial';
	ctx.fillStyle = '#fff';
	ctx.textAlign = 'left';
	var offset = Math.floor(this.target.height * 0.05);
	if (hour >= 12) {
		ctx.textBaseline = 'bottom';
		ctx.fillText('PM', offset, this.target.height - offset);
		}
	else {
		ctx.textBaseline = 'top';
		ctx.fillText('AM', offset, offset);
		}
	ctx.restore();
	};
FlipHour.prototype.constructor = FlipHour;

function update_clock() {
	var d = new Date();
	var w = ['SUN', 'MON', 'TUE', 'WED', 'THU', 'FRI', 'SAT'][d.getDay()];
	var M = ['JAN', 'FEB', 'MAR', 'APR', 'MAY', 'JUN', 'JUL', 'AUG', 'SEP', 'OCT', 'NOV', 'DEC'][d.getMonth()];
	var _d = String(d.getDate());
	var y = String(d.getFullYear());
	var h = String(d.getHours());
	var m = String(d.getMinutes());
	var s = String(d.getSeconds());
	if (m.length < 2) {
		m = '0' + m;
		}
	if (s.length < 2) {
		s = '0' + s;
		}
	if (!config.only_hhmm) {
		try { ss.flip(s); } catch (err1) { }
		}
	try { mm.flip(m); } catch (err2) { }
	try { hh.flip(h); } catch (err3) { }
	if (!config.only_hhmm) {
		try { ww.flip(w); } catch (err4) { }
		try { MM.flip(M); } catch (err5) { }
		try { dd.flip(_d); } catch (err6) { }
		try { yy.flip(y); } catch (err7) { }
		}	
	timer = window.setTimeout(update_clock, 100);
	}

function _set_wh(id, w, h) {var e = document.getElementById(id); e.style.visibility = 'visible'; e.width = w; e.height = h;}
function _hide(id, w, h) {var e = document.getElementById(id); e.style.visibility = 'hidden';}

function resize() {
	var fontname = 'Arial';
	var w = window.innerWidth;
	var h = window.innerHeight;
	var width = Math.floor((w - 5 * 4) / 3.0);
	var size = Math.floor((w - 5 * 4) / 3.0 / 3 * 2);
	var font = size + 'px "' + fontname + '"';
	var width2 = Math.floor((w - 5 * 5) / 7.0);
	var size2 = Math.floor((w - 5 * 5) / 7.0 / 3 * 2);
	var font2 = size2 + 'px "' + fontname + '"';
	if (config.only_hhmm) {
		width = Math.floor((w - 5 * 3) / 2.0);
		size = Math.floor((w - 5 * 3) / 2.0 / 3 * 2);
		font = size + 'px "' + fontname + '"';
		}
	
	_set_wh('hh', width, size);
	_set_wh('mm', width, size);
	if (!config.only_hhmm) {
		_set_wh('ss', width, size);

		_set_wh('ww', width2 * 2, size2);
		_set_wh('MM', width2 * 2, size2);
		_set_wh('dd', width2, size2);
		_set_wh('yy', width2 * 2, size2);
		}
	else {
		_hide('ss');

		_hide('ww');
		_hide('MM');
		_hide('dd');
		_hide('yy');
		}
	if (hh) {
		hh.resize(font);
		mm.resize(font);
		if (!config.only_hhmm) {
			ss.resize(font);
			
			ww.resize(font2);
			MM.resize(font2);
			dd.resize(font2);
			yy.resize(font2);
			}
		}
	else {
		hh = new FlipHour('hh', '  ', font);
		mm = new Flip('mm', '  ', font);
		ss = new Flip('ss', '  ', font);
		
		ww = new Flip('ww', '   ', font2);
		MM = new Flip('MM', '   ', font2);
		dd = new Flip('dd', '  ', font2);
		yy = new Flip('yy', '    ', font2);
		timer = window.setTimeout(update_clock, 100);
		}
	if (config.only_hhmm) {
		document.body.style.paddingTop = ((h - size) / 2) + 'px';
		document.body.style.paddingBottom = ((h - size) / 2) + 'px';
		}
	else {
		document.body.style.paddingTop = ((h - (size + size2 + 10)) / 2) + 'px';
		document.body.style.paddingBottom = ((h - (size + size2 + 10)) / 2) + 'px';
		}
	}

function load() {
	window.onresize = resize;
	window.onunload = unload;
	resize();
	document.ondblclick = dblclick;
	document.onkeyup = keyup;
	document.onselectstart = function () {return false;};
	document.onmousedown = function () {return false;};
	}

function unload() {
	window.clearTimeout(timer);
	timer = undefined;
	hh = undefined;
	mm = undefined;
	ss = undefined;
	ww = undefined;
	MM = undefined;
	dd = undefined;
	yy = undefined;
	config = undefined;
	}

function keyup(evt) {
	var ch = String.fromCharCode(evt.keyCode);

	switch (ch) {
		case ' ':
			dblclick();
			break;
		case '2':
			config.is24 = !config.is24;
			localStorage['config'] = JSON.stringify(config);
			resize();
			break;
		}
	}

function dblclick() {
	config.only_hhmm = !config.only_hhmm;
	localStorage['config'] = JSON.stringify(config);
	resize();
	}
</script>
</head>
<body onload='load()'>
<div id="row1">
<canvas id='hh'></canvas>
<canvas id='mm'></canvas>
<canvas id='ss'></canvas>
</div>
<div id="row2">
<canvas id='ww'></canvas>
<canvas id='MM'></canvas>
<canvas id='dd'></canvas>
<canvas id='yy'></canvas>
</div>
</body>
</html>
<!-- vim: set ts=2 sw=2 sts=2 ai: -->
